package com.gitee.wsl.mathematics.matrix.mat4.ext

import com.gitee.wsl.mathematics.matrix.mat4.Matrix4
import com.gitee.wsl.mathematics.vector.vec4.Vector4

/** Vec4 col = Mat4 * Vec4 row  */
infix operator fun<T:Number> Matrix4<T, *, *>.div( b: Vector4<T,*>) = div( b.x, b.y, b.z, b.w)

/** Vec4 col = Mat4 * Vec4 row  */
fun<T:Number> Matrix4<T, *, *>.div( b0: T, b1: T, b2: T, b3: T) = createVec4 { res->
    val a = this
    // invert a
    val c00 = a[2, 2] * a[3, 3] - a[3, 2] * a[2, 3]
    val c02 = a[1, 2] * a[3, 3] - a[3, 2] * a[1, 3]
    val c03 = a[1, 2] * a[2, 3] - a[2, 2] * a[1, 3]

    val c04 = a[2, 1] * a[3, 3] - a[3, 1] * a[2, 3]
    val c06 = a[1, 1] * a[3, 3] - a[3, 1] * a[1, 3]
    val c07 = a[1, 1] * a[2, 3] - a[2, 1] * a[1, 3]

    val c08 = a[2, 1] * a[3, 2] - a[3, 1] * a[2, 2]
    val c10 = a[1, 1] * a[3, 2] - a[3, 1] * a[1, 2]
    val c11 = a[1, 1] * a[2, 2] - a[2, 1] * a[1, 2]

    val c12 = a[2, 0] * a[3, 3] - a[3, 0] * a[2, 3]
    val c14 = a[1, 0] * a[3, 3] - a[3, 0] * a[1, 3]
    val c15 = a[1, 0] * a[2, 3] - a[2, 0] * a[1, 3]

    val c16 = a[2, 0] * a[3, 2] - a[3, 0] * a[2, 2]
    val c18 = a[1, 0] * a[3, 2] - a[3, 0] * a[1, 2]
    val c19 = a[1, 0] * a[2, 2] - a[2, 0] * a[1, 2]

    val c20 = a[2, 0] * a[3, 1] - a[3, 0] * a[2, 1]
    val c22 = a[1, 0] * a[3, 1] - a[3, 0] * a[1, 1]
    val c23 = a[1, 0] * a[2, 1] - a[2, 0] * a[1, 1]

    var i00 = +(a[1, 1] * c00 - a[1, 2] * c04 + a[1, 3] * c08)
    var i01 = -(a[0, 1] * c00 - a[0, 2] * c04 + a[0, 3] * c08)
    var i02 = +(a[0, 1] * c02 - a[0, 2] * c06 + a[0, 3] * c10)
    var i03 = -(a[0, 1] * c03 - a[0, 2] * c07 + a[0, 3] * c11)

    var i10 = -(a[1, 0] * c00 - a[1, 2] * c12 + a[1, 3] * c16)
    var i11 = +(a[0, 0] * c00 - a[0, 2] * c12 + a[0, 3] * c16)
    var i12 = -(a[0, 0] * c02 - a[0, 2] * c14 + a[0, 3] * c18)
    var i13 = +(a[0, 0] * c03 - a[0, 2] * c15 + a[0, 3] * c19)

    var i20 = +(a[1, 0] * c04 - a[1, 1] * c12 + a[1, 3] * c20)
    var i21 = -(a[0, 0] * c04 - a[0, 1] * c12 + a[0, 3] * c20)
    var i22 = +(a[0, 0] * c06 - a[0, 1] * c14 + a[0, 3] * c22)
    var i23 = -(a[0, 0] * c07 - a[0, 1] * c15 + a[0, 3] * c23)

    var i30 = -(a[1, 0] * c08 - a[1, 1] * c16 + a[1, 2] * c20)
    var i31 = +(a[0, 0] * c08 - a[0, 1] * c16 + a[0, 2] * c20)
    var i32 = -(a[0, 0] * c10 - a[0, 1] * c18 + a[0, 2] * c22)
    var i33 = +(a[0, 0] * c11 - a[0, 1] * c19 + a[0, 2] * c23)

    val oneOverDet = 1 / (a[0, 0] * i00 + a[0, 1] * i10 + a[0, 2] * i20 + a[0, 3] * i30)

    i00 *= oneOverDet
    i01 *= oneOverDet
    i02 *= oneOverDet
    i03 *= oneOverDet

    i10 *= oneOverDet
    i11 *= oneOverDet
    i12 *= oneOverDet
    i13 *= oneOverDet

    i20 *= oneOverDet
    i21 *= oneOverDet
    i22 *= oneOverDet
    i23 *= oneOverDet

    i30 *= oneOverDet
    i31 *= oneOverDet
    i32 *= oneOverDet
    i33 *= oneOverDet

    // a * main.getB
    res[0] = i00 * b0 + i10 * b1 + i20 * b2 + i30 * b3
    res[1] = i01 * b0 + i11 * b1 + i21 * b2 + i31 * b3
    res[2] = i02 * b0 + i12 * b1 + i22 * b2 + i32 * b3
    res[3] = i03 * b0 + i13 * b1 + i23 * b2 + i33 * b3

}